Skip to content

리스트 페이지 개발#75

Merged
Jieunsse merged 3 commits into
mainfrom
feature/list-page
Feb 23, 2026
Merged

리스트 페이지 개발#75
Jieunsse merged 3 commits into
mainfrom
feature/list-page

Conversation

@HWAN0218

Copy link
Copy Markdown
Contributor

Summary

  • 미구현된 영역 추가 개발

Issue

Scope

  • 포함

    • 변경한 내용
  • 특이사항

@HWAN0218 HWAN0218 added this to the 페이지 milestone Feb 23, 2026
@HWAN0218 HWAN0218 requested review from a team, Jieunsse, jungwon123 and yooolleee February 23, 2026 10:28
@HWAN0218 HWAN0218 self-assigned this Feb 23, 2026
@HWAN0218 HWAN0218 added the 기능추가 기능개발 및 추가할 때 사용해주세요. label Feb 23, 2026
@HWAN0218 HWAN0218 added this to workers Feb 23, 2026
@github-project-automation github-project-automation Bot moved this to 개발 대기중 in workers Feb 23, 2026
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @HWAN0218, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 풀 리퀘스트는 리스트 페이지의 기능과 사용자 경험을 전반적으로 개선하는 데 중점을 둡니다. 백엔드 API와의 통신을 더욱 견고하게 만들고, 반복 작업과 관련된 데이터 모델을 확장하여 유연한 작업 관리를 가능하게 합니다. 또한, 다양한 화면 크기에서 일관되고 직관적인 UI를 제공하기 위해 스타일을 최적화하고, 작업 목록 및 개별 작업에 대한 직접적인 편집 및 삭제 기능을 추가하여 사용자가 페이지 내에서 더 많은 작업을 수행할 수 있도록 합니다. 캘린더 팝오버와 팀 설정 메뉴를 통합하여 사용 편의성을 높였습니다.

Highlights

  • API 호출 로직 개선: fetchJson 및 fetchVoid 함수가 safeReadJson을 사용하여 응답 본문 파싱의 안정성을 높였으며, HTTP 메서드에 따른 헤더 및 credentials 처리 로직이 강화되었습니다.
  • 데이터 타입 확장: Task 타입에 startDate, frequencyType, weekDays, monthDay 등 반복 작업 및 날짜 관리를 위한 필드가 추가되어 유연성이 향상되었습니다.
  • UI/UX 개선: 모바일/태블릿 환경에서의 사이드바 레이블 오버플로우 문제 해결, TaskDetailCard 헤더 레이아웃 조정, 완료된 작업의 시각적 표시 등 다양한 CSS 개선이 이루어졌습니다.
  • 작업 목록 및 작업 관리 기능 강화: 작업 목록(TodoCard) 및 개별 작업(TaskListItem)에 대한 수정/삭제 케밥 메뉴가 추가되었고, 새로운 작업 목록 생성 시 자동 선택 기능이 구현되었습니다.
  • 캘린더 및 팀 관리 기능 추가: 캘린더 팝오버 기능이 추가되어 날짜 선택이 용이해졌으며, 팀 설정 메뉴를 통해 팀 수정/삭제 기능이 통합되었습니다.
  • React Query 훅 개선: useQuery 및 useMutation의 queryFn이 async 함수로 래핑되었고, invalidateQueries 호출 시 exact: false 옵션을 사용하여 캐시 무효화 범위가 확장되었습니다.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • src/app/(root)/list/hooks/queries.ts
    • safeReadJson 함수가 추가되어 응답 본문 파싱 안정성을 확보했습니다.
    • fetchJson 및 fetchVoid 함수가 HTTP 메서드에 따라 헤더를 동적으로 설정하고 credentials를 포함하도록 수정되었습니다.
    • ApiWeekDay 타입이 추가되었고, Task 타입에 반복 작업 관련 필드가 확장되었습니다.
    • useQuery 및 useMutation 훅의 queryFn이 async 함수로 변경되었습니다.
    • invalidateQueries 호출 시 exact: false 옵션이 추가되어 캐시 무효화 로직이 개선되었습니다.
  • src/app/(root)/list/list.module.css
    • 주석이 정리되고 불필요한 스타일 정의가 제거되었습니다.
    • TaskDetailCard 헤더 레이아웃 및 완료 상태 시 제목 스타일이 조정되었습니다.
    • 모바일/태블릿 환경에서 사이드바 레이블 오버플로우를 방지하는 스타일이 추가되었습니다.
    • 드롭다운 옵션의 disabled 상태 스타일이 추가되었습니다.
    • 팀 설정 메뉴 및 캘린더 팝오버 관련 스타일이 추가되었습니다.
  • src/app/(root)/list/page.tsx
    • useRouter 및 Calendar 컴포넌트가 임포트되었습니다.
    • 날짜/시간 및 반복 작업 관련 유틸리티 함수들이 대거 추가되었습니다.
    • selectedDateIso가 toLocalNoonIso를 사용하도록 변경되었습니다.
    • 캘린더 팝오버 상태 및 핸들러가 추가되었습니다.
    • 그룹 및 작업 목록 변경 시 선택 상태를 초기화하는 useEffect 훅이 추가되었습니다.
    • 작업 목록 미리보기 로직이 개선되었고, 빈 작업 목록 처리 로직이 추가되었습니다.
    • 작업 목록 생성/수정 모달에 todoNameDraft 상태가 도입되었습니다.
    • 작업 생성/수정 시 반복 작업 관련 필드를 처리하도록 로직이 업데이트되었습니다.
    • 외부 클릭 시 메뉴/팝오버를 닫는 useEffect 로직이 확장되었습니다.
    • 팀 설정 메뉴 및 관련 핸들러가 추가되었습니다.
    • 사이드바 컴포넌트의 props 사용 방식이 변경되었습니다.
    • TodoCard 및 TaskListItem의 케밥 메뉴 클릭 이벤트 로직이 상세화되었습니다.
    • AddTodoList 및 AddCalendarModal 컴포넌트의 initialValues 및 input props가 업데이트되었습니다.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@HWAN0218 HWAN0218 closed this Feb 23, 2026
@github-project-automation github-project-automation Bot moved this from 개발 대기중 to 개발 완료 in workers Feb 23, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

The pull request introduces several new features and improvements to the list page, including enhanced task and task list management, better date handling, and UI refinements for mobile and desktop. The changes also include updates to API call handling and data structures to support these new functionalities. Overall, the changes are well-structured and address the stated objectives of developing unimplemented areas.

Comment on lines +351 to +363
mutationFn: async (vars: {
groupId: number;
taskListId: number;
taskId: number;
body: { name?: string; description?: string; date?: string; doneAt?: string | null };
}) =>
fetchJson<Task>(
body: {
name?: string;
description?: string;
startDate?: string; //
frequencyType?: ApiFrequency;
weekDays?: ApiWeekDay[];
monthDay?: number;
doneAt?: string | null;
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The mutationFn for usePatchTask now includes startDate, frequencyType, weekDays, and monthDay in the body type. This allows for comprehensive updates to task recurrence settings. However, the body is cast to unknown as never in page.tsx which bypasses type safety. It would be better to ensure the body type is fully compatible or create a specific type for the patch body.

Comment on lines +682 to +689
const body = {
name: title,
description: memo,
startDate: startIso,
frequencyType: freq,
weekDays,
monthDay,
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The body object for patchTask.mutateAsync now includes startDate, frequencyType, weekDays, and monthDay, allowing for comprehensive updates to task recurrence. However, the body as unknown as never cast is a type safety bypass. It would be better to define a specific type for the patch body that aligns with the usePatchTask mutation function's body type.

Comment on lines +554 to +556
useEffect(() => {
queueMicrotask(() => setSelectedTaskIdState(undefined));
}, [selectedTaskListId, selectedDateIso]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Resetting selectedTaskIdState when selectedTaskListId or selectedDateIso changes is a critical improvement. This ensures that when the user switches task lists or dates, the task detail panel is correctly reset, preventing the display of stale task details.

Comment on lines +486 to +488
useEffect(() => {
queueMicrotask(() => setSelectedTaskListIdState(undefined));
}, [activeGroupId]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Resetting selectedTaskListIdState on activeGroupId change is a crucial improvement. This ensures that when a user switches teams, the task list selection is cleared, preventing stale or incorrect data from being displayed. Using queueMicrotask is a good way to defer the state update.

};
});
}, [taskLists, tasks, selectedTaskListId]);
}, [taskLists, tasks, selectedTaskListId, isGroupDetailReady]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Adding isGroupDetailReady to the dependency array for todoCardsWithPreview ensures that the memoized value is recomputed only when the group detail data is fully loaded and ready, preventing premature rendering with incomplete data.

Comment on lines +1380 to 1401
{!hasRealTaskList || tasks.length === 0 ? (
<div
key={task.id}
className={styles.taskRowClick}
onClick={(e: MouseEvent) => {
const t = e.target as HTMLElement | null;
if (isOpenDetailBlockedTarget(t)) return;
handleOpenDetail(task.id);
}}
onClick={() => (hasRealTaskList ? openTaskCreate() : openTodoCreate())}
role="button"
tabIndex={0}
>
<div style={{ position: 'relative' }}>
<TaskListItem
title={task.name}
date={selectedDateKey}
checked={!!task.doneAt}
isSelected={task.id === selectedTaskId}
commentCount={task.commentCount}
frequency={frequencyLabel(task.frequency)}
onCheckedChange={async (checked) => {
await handleToggleDone(task.id, checked);
}}
onKebabClick={() =>
setOpenedTaskMenuId((prev) => (prev === task.id ? null : task.id))
}
/>

{openedTaskMenuId === task.id ? (
<ul className={styles.taskMenu} role="menu" aria-label="할 일 메뉴">
<li>
<button
type="button"
className={styles.taskMenuItem}
onClick={() => {
setOpenedTaskMenuId(null);
openTaskEdit(task);
}}
>
수정하기
</button>
</li>
<li>
<button
type="button"
className={styles.taskMenuItem}
onClick={async () => {
setOpenedTaskMenuId(null);
await handleDeleteTask(task.id);
}}
>
삭제하기
</button>
</li>
</ul>
) : null}
</div>
<TaskListItem
title={
hasRealTaskList
? '할 일을 추가해 주세요'
: '할 일 목록을 먼저 만들어 주세요'
}
date={formatKoreanDateOnly(selectedDateKey)}
checked={false}
isSelected={false}
commentCount={0}
frequency={undefined}
onCheckedChange={() => {}}
onKebabClick={() => {}}
/>
</div>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The taskList section now conditionally renders a placeholder message and an interactive element to either create a task or a task list if no tasks or real task lists exist. This guides the user on how to get started.

Comment on lines +1434 to +1461
{openedTaskMenuId === task.id ? (
<ul className={styles.taskMenu} role="menu" aria-label="할 일 메뉴">
<li>
<button
type="button"
className={styles.taskMenuItem}
onClick={() => {
setOpenedTaskMenuId(null);
openTaskEdit(task);
}}
>
수정하기
</button>
</li>
<li>
<button
type="button"
className={styles.taskMenuItem}
onClick={async () => {
setOpenedTaskMenuId(null);
await handleDeleteTask(task.id);
}}
>
삭제하기
</button>
</li>
</ul>
) : null}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The taskMenu for individual tasks is now correctly rendered when openedTaskMenuId matches the task's ID, providing options to edit or delete the task. This improves task management within the list.

Comment on lines +1532 to +1537
input={{
props: {
value: todoNameDraft,
onChange: (e) => setTodoNameDraft(e.target.value),
autoFocus: true,
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The AddTodoList modal now uses a controlled input for the task list name, bound to todoNameDraft. This is a better React practice than direct DOM manipulation and improves form handling.

Comment on lines +743 to +779
/* ===========================
Mobile/Tablet Sidebar label overflow fix
=========================== */

.drawerFixWrap {
width: 100%;
padding-bottom: 8px;
min-width: 0;
}
/* ✅ 모바일/태블릿: 투두카드 + "할일 추가" 한 줄로 (구조 변경 없이 CSS만) */
@media (max-width: 1024px) {
/* 한 줄 컨테이너 */
.mobileTodoRow {
display: flex !important;
align-items: center !important;
gap: 12px !important;
width: 100% !important;
min-width: 0 !important;
}

.drawerFixWrap :global(button),
.drawerFixWrap :global(a) {
min-width: 0;
}

/* ✅ 모바일/태블릿: (1번처럼) 투두카드 + "할일 추가" 같은 줄 */
@media (max-width: 1024px) {
/* row는 그냥 100% */
.mobileTodoRow {
width: 100% !important;
min-width: 0 !important;
}
.drawerFixWrap :global(span),
.drawerFixWrap :global(p),
.drawerFixWrap :global(div) {
min-width: 0;
}

/* ✅ 여기서 핵심: 버튼이 같은 줄에 오도록 flex 컨테이너로 만든다 */
.mobileTodoInlineCard {
display: flex !important;
align-items: center !important;
gap: 12px !important;
.drawerFixWrap :global([class*='label']),
.drawerFixWrap :global([class*='text']),
.drawerFixWrap :global([class*='name']) {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

width: 100% !important;
flex: 1 1 auto !important;
.drawerFixWrap :global(button:hover) *,
.drawerFixWrap :global(button[aria-current='page']) *,
.drawerFixWrap :global(button[aria-selected='true']) * {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The new CSS rules under .drawerFixWrap are designed to fix overflow issues for labels within the mobile/tablet sidebar. By setting min-width: 0, overflow: hidden, text-overflow: ellipsis, and white-space: nowrap for various elements, it ensures that long text content is truncated with an ellipsis instead of overflowing, improving the UI's responsiveness and appearance.

Comment on lines +810 to 830
@media (max-width: 1024px) {
:global([class*='SidebarTeamSelect-module__'] *),
:global([class*='SidebarButton-module__'] *),
:global([class*='SidebarAddButton-module__'] *) {
max-width: 100%;
}

.todoCardShell,
.todoCardShellInner {
width: 100% !important;
:global([class*='SidebarTeamSelect-module__'] button),
:global([class*='SidebarTeamSelect-module__'] a),
:global([class*='SidebarButton-module__'] button),
:global([class*='SidebarButton-module__'] a) {
overflow: hidden;
}

/* 버튼은 고정폭 유지하면서 오른쪽 */
.mobileAddBtnWrap {
margin-left: 0 !important;
flex: 0 0 112px !important;
width: 112px !important;
:global([class*='SidebarTeamSelect-module__'] span),
:global([class*='SidebarButton-module__'] span) {
display: block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This media query block addresses overflow issues for various elements within SidebarTeamSelect, SidebarButton, and SidebarAddButton on mobile/tablet devices. By setting max-width: 100%, overflow: hidden, text-overflow: ellipsis, and white-space: nowrap, it prevents content from overflowing its container, improving the responsiveness of the sidebar components.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@HWAN0218 HWAN0218 reopened this Feb 23, 2026
@Jieunsse Jieunsse merged commit afa808e into main Feb 23, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

기능추가 기능개발 및 추가할 때 사용해주세요.

Projects

Status: 개발 완료

Development

Successfully merging this pull request may close these issues.

2 participants